package com.zenithmind.version.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.common.context.UserContext;
import com.zenithmind.common.exception.BusinessException;
import com.zenithmind.common.result.PageResult;
import com.zenithmind.common.utils.BeanCopyUtils;
import com.zenithmind.version.mapper.RepositoryMapper;
import com.zenithmind.version.mapper.RepositoryMapper.RepositoryStatistics;
import com.zenithmind.version.pojo.dto.RepositoryCreateDTO;
import com.zenithmind.version.pojo.domain.Repository;
import com.zenithmind.version.pojo.vo.RepositoryVO;
import com.zenithmind.version.service.RepositoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 仓库服务实现类
 *
 * @author ZenithMind Team
 * @since 2025-01-09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RepositoryServiceImpl extends ServiceImpl<RepositoryMapper, Repository> implements RepositoryService {

    private final RepositoryMapper repositoryMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RepositoryVO createRepository(RepositoryCreateDTO createDTO) {
        // 获取当前用户信息
        String currentUserId = UserContext.getUserId();
        String currentUserName = UserContext.getUsername();

        if (!StringUtils.hasText(currentUserId)) {
            throw new BusinessException("用户未登录");
        }

        // 检查仓库名称是否已存在
        if (!checkRepositoryNameAvailable(createDTO.getName(), currentUserId)) {
            throw new BusinessException("仓库名称已存在");
        }

        // 创建仓库实体
        Repository repository = new Repository();
        repository.setName(createDTO.getName());
        repository.setDescription(createDTO.getDescription());
        repository.setOwnerId(currentUserId);
        repository.setOwnerName(currentUserName);
        repository.setType(createDTO.getType());
        repository.setStatus(1); // 启用状态
        repository.setDefaultBranch(createDTO.getDefaultBranch());
        repository.setSize(0L);
        repository.setFileCount(0);
        repository.setCommitCount(0);
        repository.setBranchCount(1); // 默认分支
        repository.setTagCount(0);
        repository.setContributorCount(1); // 创建者
        repository.setAllowFork(createDTO.getAllowFork());
        repository.setAllowIssues(createDTO.getAllowIssues());
        repository.setAllowWiki(createDTO.getAllowWiki());
        repository.setLanguage(createDTO.getLanguage());
        repository.setHomepage(createDTO.getHomepage());
        repository.setLastActivityTime(LocalDateTime.now());
        repository.setSortOrder(0);

        // 生成克隆URL
        String cloneUrl = generateCloneUrl(repository.getName(), currentUserName);
        String sshUrl = generateSshUrl(repository.getName(), currentUserName);
        repository.setCloneUrl(cloneUrl);
        repository.setSshUrl(sshUrl);

        // 保存仓库
        boolean saved = save(repository);
        if (!saved) {
            throw new BusinessException("创建仓库失败");
        }

        // 初始化仓库
        if (createDTO.getInitReadme() == 1 || createDTO.getInitGitignore() == 1 || createDTO.getInitLicense() == 1) {
            initializeRepository(repository.getId(),
                               createDTO.getInitReadme() == 1,
                               createDTO.getInitGitignore() == 1,
                               createDTO.getGitignoreTemplate(),
                               createDTO.getInitLicense() == 1,
                               createDTO.getLicenseTemplate());
        }

        log.info("用户 {} 创建了仓库 {}", currentUserName, repository.getName());

        return convertToVO(repository);
    }

    @Override
    public PageResult<RepositoryVO> getRepositoryPage(Long current, Long size, String ownerId,
                                                     Integer type, Integer status, String keyword) {
        Page<Repository> page = new Page<>(current, size);
        IPage<Repository> repositoryPage = repositoryMapper.selectRepositoryPage(page, ownerId, type, status, keyword);

        List<RepositoryVO> records = BeanCopyUtils.copyBeanList(repositoryPage.getRecords(), RepositoryVO.class);

        // 设置额外信息
        records.forEach(this::setAdditionalInfo);

        return new PageResult<>(records, repositoryPage.getTotal(), repositoryPage.getCurrent(), repositoryPage.getSize());
    }

    @Override
    public RepositoryVO getRepositoryById(String id) {
        Repository repository = getById(id);
        if (repository == null) {
            throw new BusinessException("仓库不存在");
        }

        RepositoryVO vo = convertToVO(repository);
        setAdditionalInfo(vo);

        return vo;
    }

    @Override
    public RepositoryVO getRepositoryByNameAndOwner(String name, String ownerId) {
        Repository repository = repositoryMapper.selectByNameAndOwner(name, ownerId);
        if (repository == null) {
            throw new BusinessException("仓库不存在");
        }

        return convertToVO(repository);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateRepository(String id, RepositoryCreateDTO updateDTO) {
        Repository repository = getById(id);
        if (repository == null) {
            throw new BusinessException("仓库不存在");
        }

        // 检查权限
        String currentUserId = UserContext.getUserId();
        if (!repository.getOwnerId().equals(currentUserId)) {
            throw new BusinessException("无权限修改此仓库");
        }

        // 如果修改了名称，检查新名称是否可用
        if (!repository.getName().equals(updateDTO.getName())) {
            if (!checkRepositoryNameAvailable(updateDTO.getName(), currentUserId)) {
                throw new BusinessException("仓库名称已存在");
            }
        }

        // 更新仓库信息
        repository.setName(updateDTO.getName());
        repository.setDescription(updateDTO.getDescription());
        repository.setType(updateDTO.getType());
        repository.setDefaultBranch(updateDTO.getDefaultBranch());
        repository.setAllowFork(updateDTO.getAllowFork());
        repository.setAllowIssues(updateDTO.getAllowIssues());
        repository.setAllowWiki(updateDTO.getAllowWiki());
        repository.setLanguage(updateDTO.getLanguage());
        repository.setHomepage(updateDTO.getHomepage());

        boolean updated = updateById(repository);
        if (updated) {
            log.info("用户 {} 更新了仓库 {}", UserContext.getUsername(), repository.getName());
        }

        return updated;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteRepository(String id) {
        Repository repository = getById(id);
        if (repository == null) {
            throw new BusinessException("仓库不存在");
        }

        // 检查权限
        String currentUserId = UserContext.getUserId();
        if (!repository.getOwnerId().equals(currentUserId)) {
            throw new BusinessException("无权限删除此仓库");
        }

        boolean deleted = removeById(id);
        if (deleted) {
            log.info("用户 {} 删除了仓库 {}", UserContext.getUsername(), repository.getName());
        }

        return deleted;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean archiveRepository(String id) {
        Repository repository = getById(id);
        if (repository == null) {
            throw new BusinessException("仓库不存在");
        }

        // 检查权限
        String currentUserId = UserContext.getUserId();
        if (!repository.getOwnerId().equals(currentUserId)) {
            throw new BusinessException("无权限归档此仓库");
        }

        repository.setStatus(2); // 归档状态
        boolean updated = updateById(repository);

        if (updated) {
            log.info("用户 {} 归档了仓库 {}", UserContext.getUsername(), repository.getName());
        }

        return updated;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean unarchiveRepository(String id) {
        Repository repository = getById(id);
        if (repository == null) {
            throw new BusinessException("仓库不存在");
        }

        // 检查权限
        String currentUserId = UserContext.getUserId();
        if (!repository.getOwnerId().equals(currentUserId)) {
            throw new BusinessException("无权限取消归档此仓库");
        }

        repository.setStatus(1); // 启用状态
        boolean updated = updateById(repository);

        if (updated) {
            log.info("用户 {} 取消归档了仓库 {}", UserContext.getUsername(), repository.getName());
        }

        return updated;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RepositoryVO forkRepository(String id, String name) {
        Repository sourceRepository = getById(id);
        if (sourceRepository == null) {
            throw new BusinessException("源仓库不存在");
        }

        // 检查是否允许Fork
        if (sourceRepository.getAllowFork() == 0) {
            throw new BusinessException("此仓库不允许Fork");
        }

        String currentUserId = UserContext.getUserId();
        String currentUserName = UserContext.getUsername();

        // 检查Fork的仓库名称是否可用
        if (!checkRepositoryNameAvailable(name, currentUserId)) {
            throw new BusinessException("仓库名称已存在");
        }

        // 创建Fork仓库
        Repository forkRepository = BeanCopyUtils.copyBean(sourceRepository, Repository.class);
        forkRepository.setId(null); // 清空ID，让数据库自动生成
        forkRepository.setName(name);
        forkRepository.setOwnerId(currentUserId);
        forkRepository.setOwnerName(currentUserName);
        forkRepository.setCreateTime(LocalDateTime.now());
        forkRepository.setUpdateTime(LocalDateTime.now());
        forkRepository.setLastActivityTime(LocalDateTime.now());

        // 生成新的克隆URL
        String cloneUrl = generateCloneUrl(name, currentUserName);
        String sshUrl = generateSshUrl(name, currentUserName);
        forkRepository.setCloneUrl(cloneUrl);
        forkRepository.setSshUrl(sshUrl);

        boolean saved = save(forkRepository);
        if (!saved) {
            throw new BusinessException("Fork仓库失败");
        }

        log.info("用户 {} Fork了仓库 {} 为 {}", currentUserName, sourceRepository.getName(), name);

        return convertToVO(forkRepository);
    }

    @Override
    public List<RepositoryVO> getUserRepositories(String userId, Integer type) {
        List<Repository> repositories = repositoryMapper.selectUserRepositories(userId, type);
        return BeanCopyUtils.copyBeanList(repositories, RepositoryVO.class);
    }

    @Override
    public List<RepositoryVO> getPublicRepositories(String keyword, String language, Integer limit) {
        List<Repository> repositories = repositoryMapper.selectPublicRepositories(keyword, language, limit);
        return BeanCopyUtils.copyBeanList(repositories, RepositoryVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateRepositoryStatistics(String repositoryId) {
        // 这里应该实际计算仓库的统计信息
        // 为了简化，这里只是示例
        repositoryMapper.updateStatistics(repositoryId, 0L, 0, 0, 1, 0);
        repositoryMapper.updateLastActivityTime(repositoryId);
        return true;
    }

    @Override
    public Boolean checkRepositoryNameAvailable(String name, String ownerId) {
        Repository existing = repositoryMapper.selectByNameAndOwner(name, ownerId);
        return existing == null;
    }

    @Override
    public String getCloneUrl(String id, String protocol) {
        Repository repository = getById(id);
        if (repository == null) {
            throw new BusinessException("仓库不存在");
        }

        if ("ssh".equalsIgnoreCase(protocol)) {
            return repository.getSshUrl();
        } else {
            return repository.getCloneUrl();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean initializeRepository(String repositoryId, Boolean initReadme,
                                       Boolean initGitignore, String gitignoreTemplate,
                                       Boolean initLicense, String licenseTemplate) {
        // 这里应该实际初始化Git仓库并创建初始文件
        // 为了简化，这里只是示例
        log.info("初始化仓库 {}, README: {}, .gitignore: {}, LICENSE: {}",
                repositoryId, initReadme, initGitignore, initLicense);

        // 更新仓库统计信息
        Repository repository = getById(repositoryId);
        if (repository != null) {
            int fileCount = 0;
            if (initReadme) fileCount++;
            if (initGitignore) fileCount++;
            if (initLicense) fileCount++;

            repository.setFileCount(fileCount);
            repository.setCommitCount(1); // 初始提交
            updateById(repository);
        }

        return true;
    }

    @Override
    public RepositoryStatistics getRepositoryStatistics(String ownerId) {
        return repositoryMapper.selectStatistics(ownerId);
    }

    /**
     * 转换为VO
     */
    private RepositoryVO convertToVO(Repository repository) {
        RepositoryVO vo = BeanCopyUtils.copyBean(repository, RepositoryVO.class);
        setAdditionalInfo(vo);
        return vo;
    }

    /**
     * 设置额外信息
     */
    private void setAdditionalInfo(RepositoryVO vo) {
        // 设置类型名称
        switch (vo.getType()) {
            case 1 -> vo.setTypeName("公开");
            case 2 -> vo.setTypeName("私有");
            case 3 -> vo.setTypeName("内部");
            default -> vo.setTypeName("未知");
        }

        // 设置状态名称
        switch (vo.getStatus()) {
            case 0 -> vo.setStatusName("禁用");
            case 1 -> vo.setStatusName("启用");
            case 2 -> vo.setStatusName("归档");
            default -> vo.setStatusName("未知");
        }

        // 格式化大小
        vo.setSizeFormatted(formatSize(vo.getSize()));
    }

    /**
     * 格式化文件大小
     */
    private String formatSize(Long size) {
        if (size == null || size == 0) {
            return "0 B";
        }

        String[] units = {"B", "KB", "MB", "GB", "TB"};
        int unitIndex = 0;
        double sizeDouble = size.doubleValue();

        while (sizeDouble >= 1024 && unitIndex < units.length - 1) {
            sizeDouble /= 1024;
            unitIndex++;
        }

        return String.format("%.1f %s", sizeDouble, units[unitIndex]);
    }

    /**
     * 生成克隆URL
     */
    private String generateCloneUrl(String repositoryName, String ownerName) {
        return String.format("http://localhost:8087/git/%s/%s.git", ownerName, repositoryName);
    }

    /**
     * 生成SSH URL
     */
    private String generateSshUrl(String repositoryName, String ownerName) {
        return String.format("git@localhost:%s/%s.git", ownerName, repositoryName);
    }
}